home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / smtpcli.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  25KB  |  1,088 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. /* Mods by G1EMM and PA0GRI */
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #include <time.h>
  17. #include <setjmp.h>
  18. #ifdef UNIX
  19. #include <sys/types.h>
  20. #endif
  21. #ifdef    AMIGA
  22. #include <stat.h>
  23. #else
  24. #include <sys/stat.h>
  25. #endif
  26. #ifdef    __TURBOC__
  27. #include <dir.h>
  28. #include <io.h>
  29. #endif
  30. #include "global.h"
  31. #include "config.h"
  32. #ifdef    ANSIPROTO
  33. #include <stdarg.h>
  34. #endif
  35. #include "mbuf.h"
  36. #include "cmdparse.h"
  37. #include "proc.h"
  38. #include "socket.h"
  39. #ifdef    LZW
  40. #include "lzw.h"
  41. #endif
  42. #include "timer.h"
  43. #include "netuser.h"
  44. #include "smtp.h"
  45. #include "dirutil.h"
  46. #include "commands.h"
  47. #include "session.h"
  48. #include "files.h"
  49.  
  50. static struct timer Smtpcli_t;
  51. static int32 Gateway;
  52.  
  53. #ifdef SMTPTRACE
  54. static unsigned short Smtptrace = 0;        /* used for trace level */
  55. static int dosmtptrace __ARGS((int argc,char *argv[],void *p));
  56. static char smtp_recv[] = "smtpcli recv: %s\n";
  57. #endif
  58.  
  59. static unsigned  short Smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  60. static int Smtpsessions = 0;        /* number of client connections
  61.                     * currently open */
  62. #ifdef    LZW
  63. int Smtpslzw = 1;
  64. int Smtpclzw = 1;
  65. static int Smtpbatch = 1;
  66. #else
  67. static int Smtpbatch = 0;
  68. #endif
  69. int    Smtpmode = 0;
  70.  
  71. int    Smtpquiet = 0;
  72. int    UseMX = 0;            /* use MX records in domain lookup */
  73.  
  74. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  75.  
  76. static void del_job __ARGS((struct smtp_job *jp));
  77. static void del_session __ARGS((struct smtpcli *cb));
  78. static int dogateway __ARGS((int argc,char *argv[],void *p));
  79. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  80. static int dotimer __ARGS((int argc,char *argv[],void *p));
  81. static int doquiet __ARGS((int argc,char *argv[],void *p));
  82. #ifdef LZW
  83. static int doclzw __ARGS((int argc,char *argv[],void *p));
  84. static int doslzw __ARGS((int argc,char *argv[],void *p));
  85. #endif
  86. static int dousemx __ARGS((int argc,char *argv[],void *p));
  87. static int dosmtpkill __ARGS((int argc,char *argv[],void *p));
  88. static int dosmtplist __ARGS((int argc,char *argv[],void *p));
  89. static int dobatch __ARGS((int argc,char *argv[],void *p));
  90. static void execjobs __ARGS((void));
  91. static int getresp __ARGS((struct smtpcli *ftp,int mincode));
  92. static void logerr __ARGS((struct smtpcli *cb,char *line));
  93. static struct smtpcli *lookup __ARGS((int32 destaddr));
  94. static struct smtpcli *newcb __ARGS((void));
  95. static int next_job __ARGS((struct smtpcli *cb));
  96. static void retmail __ARGS((struct smtpcli *cb));
  97. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  98. static int smtpsendfile __ARGS((struct smtpcli *cb));
  99. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  100. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  101. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  102. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  103. static int dosmtpt4 __ARGS((int argc,char *argv[],void *p));
  104.  
  105. static struct cmds Smtpcmds[] = {
  106.     "batch",    dobatch,    0,    0,    NULLCHAR,
  107.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  108.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  109.     "kick",        smtpkick,    0,    0,    NULLCHAR,
  110.     "kill",        dosmtpkill,    0,    2,    "kill <jobnumber>",
  111.     "list",        dosmtplist,    0,    0,    NULLCHAR,
  112.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  113.     "quiet",    doquiet,    0,    0,    NULLCHAR,
  114. #ifdef    LZW
  115.     "reclzw",    doslzw,        0,    0,    NULLCHAR,
  116.     "sendlzw",    doclzw,        0,    0,    NULLCHAR,
  117. #endif
  118.     "timer",    dotimer,    0,    0,    NULLCHAR,
  119. #ifdef SMTPTRACE
  120.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  121. #endif
  122.     "t4",       dosmtpt4,   0,  0,  NULLCHAR,
  123.     "usemx",    dousemx,    0,    0,    NULLCHAR,
  124.     NULLCHAR,
  125. };
  126.  
  127. int
  128. dosmtp(argc,argv,p)
  129. int argc;
  130. char *argv[];
  131. void *p;
  132. {
  133.     return subcmd(Smtpcmds,argc,argv,p);
  134. }
  135.  
  136. int Smtpt4;
  137.  
  138. static int
  139. dosmtpt4(argc,argv,p)
  140. int argc;
  141. char *argv[];
  142. void *p;
  143. {
  144.     return setint(&Smtpt4,"SMTP T4",argc,argv);
  145. }
  146.  
  147. static int
  148. dobatch(argc,argv,p)
  149. int argc;
  150. char *argv[];
  151. void *p;
  152. {
  153.     return setbool(&Smtpbatch,"SMTP batching",argc,argv);
  154. }
  155.  
  156. #ifdef LZW
  157. static int
  158. doclzw(argc,argv,p)
  159. int argc;
  160. char *argv[];
  161. void *p;
  162. {
  163.     return setbool(&Smtpclzw,"SMTP send lzw",argc,argv);
  164. }
  165. #endif
  166.  
  167. static int
  168. doquiet(argc,argv,p)
  169. int argc;
  170. char *argv[];
  171. void *p;
  172. {
  173.     return setbool(&Smtpquiet,"SMTP quiet",argc,argv);
  174. }
  175.  
  176. #ifdef LZW
  177. static int
  178. doslzw(argc,argv,p)
  179. int argc;
  180. char *argv[];
  181. void *p;
  182. {
  183.     return setbool(&Smtpslzw,"SMTP recv lzw",argc,argv);
  184. }
  185. #endif
  186.  
  187. static int
  188. dousemx(argc,argv,p)
  189. int argc;
  190. char *argv[];
  191. void *p;
  192. {
  193.     return setbool(&UseMX,"MX records used",argc,argv);
  194. }
  195. static int
  196. dosmtpmaxcli(argc,argv,p)
  197. int argc;
  198. char *argv[];
  199. void *p;
  200. {
  201.     return setshort(&Smtpmaxcli,"Max clients",argc,argv);
  202. }
  203.  
  204. static int
  205. setsmtpmode(argc,argv,p)
  206. int argc;
  207. char *argv[];
  208. void *p;
  209. {
  210.     if (argc < 2) {
  211.         tprintf("smtp mode: %s\n",
  212.             (Smtpmode & QUEUE) ? "queue" : "route");
  213.     } else {
  214.         switch(*argv[1]) {
  215.         case 'q':
  216.             Smtpmode |= QUEUE;
  217.             break;
  218.         case 'r':
  219.             Smtpmode &= ~QUEUE;
  220.             break;
  221.         default:
  222.             tprintf("Usage: smtp mode [queue | route]\n");
  223.             break;
  224.         }
  225.     }
  226.     return 0;
  227. }
  228. static int
  229. dogateway(argc,argv,p)
  230. int argc;
  231. char *argv[];
  232. void *p;
  233. {
  234.     int32 n;
  235.  
  236.     if(argc < 2){
  237.         tprintf("%s\n",inet_ntoa(Gateway));
  238.     } else if((n = resolve(argv[1])) == 0){
  239.         tprintf(Badhost,argv[1]);
  240.         return 1;
  241.     } else
  242.         Gateway = n;
  243.     return 0;
  244. }
  245.  
  246. #ifdef SMTPTRACE
  247. static int
  248. dosmtptrace(argc,argv,p)
  249. int argc;
  250. char *argv[];
  251. void *p;
  252. {
  253.     return setshort(&Smtptrace,"SMTP tracing",argc,argv);
  254. }
  255. #endif
  256.  
  257. /* list jobs waiting to be sent in the mqueue */
  258. static int
  259. dosmtplist(argc,argv,p)
  260. int argc;
  261. char *argv[];
  262. void *p;
  263. {
  264.     char tstring[80];
  265.     char line[20];
  266.     char host[LINELEN];
  267.     char to[LINELEN];
  268.     char from[LINELEN];
  269.     char *cp;
  270.     char status;
  271.     int flowsave;
  272.     struct stat stbuf;
  273.     struct tm *tminfo;
  274.     FILE *fp;
  275.  
  276.     flowsave = Current->flowmode;
  277.     Current->flowmode = 1; /* Enable the more mechanism */
  278. #ifdef    TABS
  279.     tprintf("S\tJob   Size Date  Time  Host\t\tFrom\n");
  280. #else
  281.     tprintf("S       Job   Size Date  Time  Host              From\n");
  282. #endif
  283.     filedir(Mailqueue,0,line);
  284.     while(line[0] != '\0') {
  285.         sprintf(tstring,"%s/%s",Mailqdir,line);
  286.         if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
  287.             tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
  288.             continue;
  289.         }
  290.         if ((cp = strrchr(line,'.')) != NULLCHAR)
  291.             *cp = '\0';
  292.         sprintf(tstring,"%s/%s.lck",Mailqdir,line);
  293.         if (access(tstring,0))
  294.             status = ' ';
  295.         else
  296.             status = 'L';
  297.         sprintf(tstring,"%s/%s.txt",Mailqdir,line);
  298.         stat(tstring,&stbuf);
  299.         tminfo = localtime(&stbuf.st_ctime);
  300.         fgets(host,sizeof(host),fp);
  301.         rip(host);
  302.         fgets(from,sizeof(from),fp);
  303.         rip(from);
  304. #ifdef    TABS
  305.         tprintf("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n\t",
  306. #else
  307.         tprintf("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n        ",
  308. #endif
  309.             status, line, stbuf.st_size,
  310.             tminfo->tm_mon+1,
  311.             tminfo->tm_mday,
  312.             tminfo->tm_hour,
  313.             tminfo->tm_min,
  314.             host,from);
  315.         while (fgets(to,sizeof(to),fp) != NULLCHAR) {
  316.             rip(to);
  317.             tprintf("%s ",to);
  318.         }
  319.         tprintf("\n");
  320.         (void) fclose(fp);
  321.         pwait(NULL);
  322.         filedir(Mailqueue,1,line);
  323.     }
  324.     Current->flowmode = flowsave;
  325.     return 0;
  326. }
  327.  
  328. /* kill a job in the mqueue */
  329. static int
  330. dosmtpkill(argc,argv,p)
  331. int argc;
  332. char *argv[];
  333. void *p;
  334. {
  335.     char s[SLINELEN];
  336.     char *cp,c;
  337.     sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
  338.     cp = strrchr(s,'.');
  339.     if (!access(s,0)) {
  340.         Current->ttystate.echo = Current->ttystate.edit = 0;
  341.         c = keywait("Warning, job is locked by SMTP. Remove (y/n)? ",0);
  342.         Current->ttystate.echo = Current->ttystate.edit = 1;
  343.         if (c != 'y')
  344.             return 0;
  345.         (void) unlink(s);
  346.     }
  347.     strcpy(cp,".wrk");
  348.     if (unlink(s))
  349.         tprintf("Job id %s not found\n",argv[1]);
  350.     strcpy(cp,".txt");
  351.     (void) unlink(s);
  352.     return 0;
  353. }
  354.  
  355. /* Set outbound spool scan interval */
  356. static int
  357. dotimer(argc,argv,p)
  358. int argc;
  359. char *argv[];
  360. void *p;
  361. {
  362.     if(argc < 2){
  363.         tprintf("smtp timer = %lu/%lu\n",
  364.         read_timer(&Smtpcli_t)/1000L,
  365.         dur_timer(&Smtpcli_t)/1000L);
  366.         return 0;
  367.     }
  368.     Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
  369.     Smtpcli_t.arg = NULL;        /* dummy value */
  370.     set_timer(&Smtpcli_t,atol(argv[1])*1000L);    /* set timer duration */
  371.     start_timer(&Smtpcli_t);        /* and fire it up */
  372.     return 0;
  373. }
  374.  
  375. static int
  376. smtpkick(argc,argv,p)
  377. int argc;
  378. char *argv[];
  379. void *p;
  380. {
  381.     int32 addr = 0;
  382.     if(argc > 1 && (addr = resolve(argv[1])) == 0){
  383.         tprintf(Badhost,argv[1]);
  384.         return 1;
  385.     }
  386.     smtptick((void *)addr);
  387.     return 0;
  388. }
  389.  
  390. /* This is the routine that gets called every so often to do outgoing
  391.  * mail processing. When called with a null argument, it runs the entire
  392.  * queue; if called with a specific non-zero IP address from the remote
  393.  * kick server, it only starts up sessions to that address.
  394.  */
  395. int
  396. smtptick(t)
  397. void *t;
  398. {
  399.     register struct smtpcli *cb;
  400.     struct smtp_job *jp;
  401.     struct list *ap;
  402.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  403.     char    from[LINELEN], to[LINELEN];
  404.     char *cp, *cp1;
  405.     int32 destaddr,target;
  406.     FILE *wfile;
  407.  
  408.     target = (int32)t;
  409. #ifdef SMTPTRACE
  410.     if (Smtptrace > 5)
  411.         printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
  412. #endif
  413. #ifndef UNIX
  414.     if(availmem() < Memthresh){
  415.         /* Memory is tight, don't do anything */
  416.         /* Restart timer */
  417.         start_timer(&Smtpcli_t);
  418.         return 0;
  419.     }
  420. #endif
  421.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  422.         filedir(Mailqueue,1,wfilename)){
  423.  
  424.         /* save the prefix of the file name which it job id */
  425.         cp = wfilename;
  426.         cp1 = prefix;
  427.         while (*cp && *cp != '.')
  428.             *cp1++ = *cp++;
  429.         *cp1 = '\0';
  430.  
  431.         /* lock this file from the smtp daemon */
  432.         if (mlock(Mailqdir,prefix))
  433.             continue;
  434.  
  435.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  436.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  437.             /* probably too many open files */
  438.             (void) rmlock(Mailqdir,prefix);
  439.             /* continue to next message. The failure
  440.             * may be temporary */
  441.             continue;
  442.         }
  443.  
  444.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  445.         rip(tmpstring);
  446.  
  447.         if ((destaddr = mailroute(tmpstring)) == 0) {
  448.             fclose(wfile);
  449.             printf("** smtp: Unknown address %s\n",tmpstring);
  450.             (void) rmlock(Mailqdir,prefix);
  451.             continue;
  452.         }
  453.         if(target != 0 && destaddr != target){
  454.             fclose(wfile);
  455.             (void) rmlock(Mailqdir,prefix);
  456.             continue;    /* Not the proper target of a kick */
  457.         }
  458.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  459.             /* there are enough processes running already */
  460.             if (Smtpsessions >= Smtpmaxcli) {
  461. #ifdef SMTPTRACE
  462.                 if (Smtptrace) {
  463.                     printf("smtp daemon: too many processes\n");
  464.                 }
  465. #endif
  466.                 fclose(wfile);
  467.                 (void) rmlock(Mailqdir,prefix);
  468.                 break;
  469.             }
  470.             if ((cb = newcb()) == NULLSMTPCLI) {
  471.                 fclose(wfile);
  472.                 (void) rmlock(Mailqdir,prefix);
  473.                 break;
  474.             } 
  475.             cb->ipdest = destaddr;
  476.             cb->destname = strdup(tmpstring);
  477.         } else {
  478.             if(cb->lock){
  479.                 /* This system is already is sending mail lets not
  480.                 * interfere with its send queue.
  481.                 */
  482.                 fclose(wfile);
  483.                 (void) rmlock(Mailqdir,prefix);
  484.                 continue;
  485.             }
  486.         }
  487.  
  488.         (void) fgets(from,LINELEN,wfile);    /* read from */
  489.         rip(from);
  490.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  491.             fclose(wfile);
  492.             (void) rmlock(Mailqdir,prefix);
  493.             del_session(cb);
  494.             break;
  495.         }
  496.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  497.             rip(to);
  498.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  499.                 fclose(wfile);
  500.                 del_session(cb);
  501.             }
  502.         }
  503.         fclose(wfile);
  504. #ifdef SMTPTRACE
  505.         if (Smtptrace > 1) {
  506.             printf("queue job %s From: %s To:",prefix,from);
  507.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  508.                 printf(" %s",ap->val);
  509.             printf("\n");
  510.         }
  511. #endif
  512.     }
  513.  
  514.     /* start sending that mail */
  515.     execjobs();
  516.  
  517.     /* Restart timer */
  518.     start_timer(&Smtpcli_t);
  519.     return 0;
  520. }
  521.  
  522. /* This is the master state machine that handles a single SMTP transaction.
  523.  * It is called with a queue of jobs for a particular host.
  524.  * The logic is complicated by the "Smtpbatch" variable, which controls
  525.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  526.  * SMTP commands are sent in one swell foop before waiting for any of
  527.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  528.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  529.  */
  530. static void
  531. smtp_send(unused,cb1,p)
  532. int unused;
  533. void *cb1;
  534. void *p;
  535. {
  536.     register struct smtpcli *cb;
  537.     register struct list *tp;
  538.     struct sockaddr_in fsocket;
  539.     char *cp;
  540.     int rcode;
  541.     int rcpts;
  542.     int goodrcpt;
  543.     int i;
  544.     int smtpbatch;
  545.     int init = 1;
  546. #ifdef    LZW
  547.     int lzwmode, lzwbits;
  548.     extern int16 Lzwbits;
  549.     extern int Lzwmode;
  550. #endif
  551.  
  552.     cb = (struct smtpcli *)cb1;
  553.     cb->lock = 1;
  554.     fsocket.sin_family = AF_INET;
  555.     fsocket.sin_addr.s_addr = cb->ipdest;
  556.     fsocket.sin_port = IPPORT_SMTP;
  557.  
  558.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  559.     sockmode(cb->s,SOCK_ASCII);
  560.     setflush(cb->s,-1);    /* We'll explicitly flush before reading */
  561. #ifdef SMTPTRACE
  562.     if (Smtptrace) 
  563.         printf("SMTP client Trying...\n");
  564. #endif
  565.     /* Set a timeout for this connection */
  566.     alarm(Smtpt4 * 1000L);
  567.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
  568.         alarm(0L);
  569.         close_s(cb->s);     /* to make sure it's closed */
  570.         if(Smtpt4 && Gateway && (fsocket.sin_addr.s_addr != Gateway) ) {
  571.             /* Try it via the gateway */
  572.             fsocket.sin_addr.s_addr = Gateway;
  573.             cb->s = socket(AF_INET,SOCK_STREAM,0);
  574.             sockmode(cb->s,SOCK_ASCII);
  575.             setflush(cb->s,-1); /* We'll explicitly flush before reading */
  576. #ifdef SMTPTRACE
  577.             if (Smtptrace)
  578.                 printf("SMTP client Trying gateway...\n");
  579. #endif
  580.             /* Set a timeout for this connection */
  581.             alarm(Smtpt4 * 1000L);
  582.             if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
  583.                 alarm(0L);
  584.                 cp = sockerr(cb->s);
  585.                 close_s(cb->s);     /* to make sure it's closed */
  586. #ifdef SMTPTRACE
  587.                 if (Smtptrace)
  588.                     printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  589. #endif
  590.                 log(cb->s,"SMTP %s Connect failed: %s",psocket(&fsocket),
  591.                     cp != NULLCHAR ? cp : "");
  592.                 goto quit;
  593.             }
  594.         } else {
  595.             goto quit;
  596.         }
  597.     }
  598.     alarm(0L);
  599. #ifdef SMTPTRACE
  600.     if (Smtptrace)
  601.         printf("Connected\n");
  602. #endif
  603.  
  604. #ifdef    LZW
  605.     rcode = getresp(cb,200);
  606.     if(rcode == -1 || rcode >= 400)
  607.         goto quit;
  608.  
  609.     if(Smtpclzw) {
  610.         char cp[LINELEN];
  611.         sendcmd(cb,"XLZW %d %d\n",Lzwbits,Lzwmode);
  612.         usflush(cb->s);
  613.         if(recvline(cb->s,cp,sizeof(cp)) == -1)
  614.             goto quit;
  615.         rip(cp);
  616. #ifdef    SMTPTRACE
  617.         if(Smtptrace)
  618.             printf(smtp_recv,cp);/* Display to user */
  619. #endif
  620.         rcode = lzwmode = lzwbits = 0;
  621.         sscanf(cp,"%d %d %d",&rcode,&lzwbits,&lzwmode);
  622.         if((rcode >= 200) && (rcode < 300)) {
  623.             smtpbatch = 1;
  624.             if(lzwmode != Lzwmode || lzwbits != Lzwbits) {
  625.                 lzwmode = LZWCOMPACT;
  626.                 lzwbits = LZWBITS;
  627.             }
  628.             lzwinit(cb->s,lzwbits,lzwmode);
  629.         } else {
  630.             smtpbatch = Smtpbatch;
  631.         }
  632.     } else {
  633.         smtpbatch = Smtpbatch;
  634.     }
  635. #else
  636.     smtpbatch = Smtpbatch;
  637.     if(!smtpbatch){
  638.         rcode = getresp(cb,200);
  639.         if(rcode == -1 || rcode >= 400)
  640.             goto quit;
  641.     }
  642. #endif
  643.     /* Say HELO */
  644.     sendcmd(cb,"HELO %s\n",Hostname);
  645.     if(!smtpbatch){
  646.         rcode = getresp(cb,200);
  647.         if(rcode == -1 || rcode >= 400)
  648.             goto quit;
  649.     }
  650.     do {    /* For each message... */
  651.  
  652.         /* if this file open fails, skip it */
  653.         if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  654.             continue;
  655.  
  656.         /* Send MAIL and RCPT commands */
  657.         sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
  658.         if(!smtpbatch){
  659.             rcode = getresp(cb,200);
  660.             if(rcode == -1 || rcode >= 400)
  661.                 goto quit;
  662.         }
  663.         rcpts = 0;
  664.         goodrcpt = 0;
  665.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  666.             sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
  667.             if(!smtpbatch){
  668.                 rcode = getresp(cb,200);
  669.                 if(rcode == -1)
  670.                     goto quit;
  671.                 if(rcode < 400)
  672.                     goodrcpt = 1; /* At least one good */
  673.             }
  674.             rcpts++;
  675.         }
  676.         /* Send DATA command */
  677.         sendcmd(cb,"DATA\n");
  678.         if(!smtpbatch){
  679.             rcode = getresp(cb,200);
  680.             if(rcode == -1 || rcode >= 400)
  681.                 goto quit;
  682.         }
  683.         if(smtpbatch){
  684.             /* Now wait for the responses to come back. The first time
  685.              * we do this, we wait first for the start banner and
  686.              * HELO response. In any case, we wait for the response to
  687.              * the MAIL command here.
  688.              */
  689. #ifdef    LZW
  690.             for(i= init ? 2 : 1;i > 0;i--){
  691. #else
  692.             for(i= init ? 3 : 1;i > 0;i--){
  693. #endif
  694.                 rcode = getresp(cb,200);
  695.                 if(rcode == -1 || rcode >= 400)
  696.                     goto quit;
  697.             }
  698.             init = 0;
  699.  
  700.             /* Now process the responses to the RCPT commands */
  701.             for(i=rcpts;i!=0;i--){
  702.                 rcode = getresp(cb,200);
  703.                 if(rcode == -1)
  704.                     goto quit;
  705.                 if(rcode < 400)
  706.                     goodrcpt = 1; /* At least one good */
  707.             }
  708.             /* And finally get the response to the DATA command.
  709.              * Some servers will return failure here if no recipients
  710.              * are valid, some won't.
  711.              */
  712.             rcode = getresp(cb,200);
  713.             if(rcode == -1 || rcode >= 400)
  714.                 goto quit;
  715.  
  716.             /* check for no good rcpt on the list */
  717.             if (goodrcpt == 0){
  718.                 sendcmd(cb,".\n");  /* Get out of data mode */
  719.                 goto quit;
  720.             }
  721.         }
  722.         /* Send the file. This also closes it */
  723.         smtpsendfile(cb);
  724.  
  725.         /* Wait for the OK response */
  726.         rcode = getresp(cb,200);
  727.         if(rcode == -1)
  728.             goto quit;
  729.         if((rcode >= 200 && rcode < 300) || rcode >= 500){
  730.             /* if a good transfer or permanent failure remove job */
  731.  
  732.             if (cb->errlog != NULLLIST)
  733.                 retmail(cb);
  734.             /* Unlink the textfile */
  735.             (void) unlink(cb->tname);
  736.             (void) unlink(cb->wname);    /* unlink workfile */
  737.             log(cb->s,"SMTP sent job %s To: %s From: %s",
  738.              cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  739.         }
  740.     } while(next_job(cb));
  741. quit:
  742.     sendcmd(cb,"QUIT\n");
  743.     if (cb->errlog != NULLLIST){
  744.         retmail(cb);
  745.         (void) unlink(cb->wname);    /* unlink workfile */
  746.         (void) unlink(cb->tname);    /* unlink text */
  747.     }
  748.     (void) close_s(cb->s);
  749.     if(cb->tfile != NULLFILE)
  750.         fclose(cb->tfile);
  751.     cb->lock = 0;
  752.     del_session(cb);
  753. }
  754.  
  755. /* free the message struct and data */
  756. static void
  757. del_session(cb)
  758. register struct smtpcli *cb;
  759. {
  760.     register struct smtp_job *jp,*tp;
  761.     register int i;
  762.  
  763.     if (cb == NULLSMTPCLI)
  764.         return;
  765.     for(i=0; i<MAXSESSIONS; i++) 
  766.         if(cli_session[i] == cb) {
  767.             cli_session[i] = NULLSMTPCLI;
  768.             break;
  769.         }
  770.  
  771.     free(cb->wname);
  772.     free(cb->tname);
  773.     free(cb->destname);
  774.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  775.             tp = jp->next;
  776.             del_job(jp);
  777.     }
  778.     del_list(cb->errlog);
  779.     free((char *)cb);
  780.     Smtpsessions--;    /* number of connections active */
  781. }
  782.  
  783. static void
  784. del_job(jp)
  785. register struct smtp_job *jp;
  786. {
  787.     if ( *jp->jobname != '\0')
  788.         (void) rmlock(Mailqdir,jp->jobname);
  789.     free(jp->from);
  790.     del_list(jp->to);
  791.     free((char *)jp);
  792. }
  793.  
  794. /* delete a list of list structs */
  795. void
  796. del_list(lp)
  797. struct list *lp;
  798. {
  799.     register struct list *tp, *tp1;
  800.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  801.         tp1 = tp->next;
  802.         free(tp->val);
  803.         free((char *)tp);
  804.     }
  805. }
  806.  
  807. /* stub for calling mdaemon to return message to sender */
  808. static void
  809. retmail(cb)
  810. struct smtpcli *cb;
  811. {
  812.     FILE *infile;
  813. #ifdef SMTPTRACE
  814.     if (Smtptrace > 5) {
  815.         printf("smtp job %s returned to sender\n",cb->wname);
  816.     }
  817. #endif
  818.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  819.         return;
  820.     mdaemon(infile,cb->jobq->from,cb->errlog,1);
  821.     fclose(infile);
  822. }
  823.  
  824. /* look to see if a smtp control block exists for this ipdest */
  825. static struct smtpcli *
  826. lookup(destaddr)
  827. int32 destaddr;
  828. {
  829.     register int i;
  830.  
  831.     for(i=0; i<MAXSESSIONS; i++) {
  832.         if (cli_session[i] == NULLSMTPCLI)
  833.             continue;
  834.         if(cli_session[i]->ipdest == destaddr)
  835.             return cli_session[i];
  836.     }
  837.     return NULLSMTPCLI;
  838. }
  839.  
  840. /* create a new  smtp control block */
  841. static struct smtpcli *
  842. newcb()
  843. {
  844.     register int i;
  845.     register struct smtpcli *cb;
  846.  
  847.     for(i=0; i<MAXSESSIONS; i++) {
  848.         if(cli_session[i] == NULLSMTPCLI) {
  849.             cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
  850.             cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  851.             cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  852.             cli_session[i] = cb;
  853.             Smtpsessions++;    /* number of connections active */
  854.             return(cb);
  855.         }
  856.     }
  857.     return NULLSMTPCLI;
  858. }
  859.  
  860. static void
  861. execjobs()
  862. {
  863.     register struct smtpcli *cb;
  864.     register int i;
  865.  
  866.     for(i=0; i<MAXSESSIONS; i++) {
  867.         cb = cli_session[i];
  868.         if (cb == NULLSMTPCLI) 
  869.             continue;
  870.         if(cb->lock)
  871.             continue;
  872.  
  873.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  874.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  875.  
  876.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL,0);
  877.  
  878. #ifdef SMTPTRACE
  879.         if (Smtptrace) 
  880.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  881. #endif
  882.  
  883.  
  884.     }
  885. }
  886.     
  887. /* add this job to control block queue */
  888. static struct smtp_job *
  889. setupjob(cb,id,from)
  890. struct smtpcli *cb;
  891. char *id,*from;
  892. {
  893.     register struct smtp_job *p1,*p2;
  894.  
  895.     p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
  896.     p1->from = strdup(from);
  897.     strcpy(p1->jobname,id);
  898.     /* now add to end of jobq */
  899.     if ((p2 = cb->jobq) == NULLJOB)
  900.         cb->jobq = p1;
  901.     else {
  902.         while(p2->next != NULLJOB)
  903.             p2 = p2->next;
  904.         p2->next = p1;
  905.     }
  906.     return p1;
  907. }
  908.  
  909. /* called to advance to the next job */
  910. static int
  911. next_job(cb)
  912. register struct smtpcli *cb;
  913. {
  914.     register struct smtp_job *jp;
  915.  
  916.     jp = cb->jobq->next;
  917.     del_job(cb->jobq);
  918.     /* remove the error log of previous message */
  919.     del_list(cb->errlog);
  920.     cb->errlog = NULLLIST;
  921.     cb->jobq = jp;
  922.     if (jp == NULLJOB)
  923.         return 0;
  924.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  925.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  926. #ifdef SMTPTRACE
  927.     if (Smtptrace > 5) {
  928.         printf("sending job %s\n",jp->jobname);
  929.     }
  930. #endif
  931.         return 1;
  932.  
  933. }
  934.  
  935.  
  936. /* Mail routing function. For now just use the hosts file */
  937. int32
  938. mailroute(dest)
  939. char *dest;
  940. {
  941.     int32 destaddr = 0L;
  942.  
  943. #ifdef SMTPTRACE
  944.     if (Smtptrace > 6)
  945.         printf("MX lookup for = %s\n",dest);
  946. #endif
  947.     /* look up address or use the gateway */
  948.     if(UseMX){
  949.         destaddr = resolve_mx(dest);
  950. #ifdef SMTPTRACE
  951.         if (Smtptrace > 6)
  952.             printf("MX lookup returned = %s\n",inet_ntoa(destaddr));
  953. #endif
  954.     }
  955.     if(destaddr == 0L)
  956.         if((destaddr = resolve(dest)) == 0L)
  957.             if (Gateway != 0) 
  958.                 destaddr = Gateway; /* Use the gateway  */
  959. #ifdef SMTPTRACE
  960.     if (Smtptrace > 6)
  961.         printf("Mailroute returned = %s\n",inet_ntoa(destaddr));
  962. #endif
  963.     return destaddr;
  964.     
  965. }
  966.  
  967. /* save line in error list */
  968. static void
  969. logerr(cb,line)
  970. struct smtpcli *cb;
  971. char *line;
  972. {
  973.     register struct list *lp,*tp;
  974.     tp = (struct list *)callocw(1,sizeof(struct list));
  975.     tp->val = strdup(line);
  976.     /* find end of list */
  977.     if ((lp = cb->errlog) == NULLLIST)
  978.         cb->errlog = tp;
  979.     else {
  980.         while(lp->next != NULLLIST)
  981.             lp = lp->next;
  982.         lp->next = tp;
  983.     }
  984. }
  985.  
  986. static int
  987. smtpsendfile(cb)
  988. register struct smtpcli *cb;
  989. {
  990.     int error = 0;
  991.  
  992.     strcpy(cb->buf,"\n");
  993.     while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULLCHAR) {
  994.         /* Escape a single '.' character at the beginning of a line */
  995.         if(strcmp(cb->buf,".\n") == 0)
  996.             usputc(cb->s,'.');
  997.         usputs(cb->s,cb->buf);
  998.     }
  999.     fclose(cb->tfile);
  1000.     cb->tfile = NULLFILE;
  1001.     /* Send the end-of-message command */
  1002.     if(cb->buf[strlen(cb->buf)-1] == '\n')
  1003.         sendcmd(cb,".\n");
  1004.     else
  1005.         sendcmd(cb,"\n.\n");
  1006.     return error;
  1007. }
  1008. /* do a printf() on the socket with optional local tracing */
  1009. #ifdef    ANSIPROTO
  1010. static void
  1011. sendcmd(struct smtpcli *cb,char *fmt, ...)
  1012. {
  1013.     va_list args;
  1014.  
  1015.     va_start(args,fmt);
  1016. #ifdef    SMTPTRACE
  1017.     if(Smtptrace){
  1018.         printf("smtp sent: ");
  1019.         vprintf(fmt,args);
  1020.     }
  1021. #endif
  1022.     vsprintf(cb->buf,fmt,args);
  1023.     usputs(cb->s,cb->buf);
  1024.     va_end(args);
  1025. }
  1026. #else
  1027. static void
  1028. sendcmd(cb,fmt,arg1,arg2,arg3,arg4)
  1029. struct smtpcli *cb;
  1030. char *fmt;
  1031. int arg1,arg2,arg3,arg4;
  1032. {
  1033. #ifdef    SMTPTRACE
  1034.     if(Smtptrace){
  1035.         printf("smtp sent: ");
  1036.         printf(fmt,arg1,arg2,arg3,arg4);
  1037.     }
  1038. #endif
  1039.     sprintf(cb->buf,fmt,arg1,arg2,arg3,arg4);
  1040.     usputs(cb->s,cb->buf);
  1041. }
  1042. #endif
  1043.  
  1044. /* Wait for, read and display response from server. Return the result code. */
  1045. static int
  1046. getresp(cb,mincode)
  1047. struct smtpcli *cb;
  1048. int mincode;    /* Keep reading until at least this code comes back */
  1049. {
  1050.     int rval;
  1051.     char line[LINELEN];
  1052.  
  1053.     usflush(cb->s);
  1054.     for(;;){
  1055.         /* Get line */
  1056.         if(recvline(cb->s,line,LINELEN) == -1){
  1057.             rval = -1;
  1058.             break;
  1059.         }
  1060.         rip(line);        /* Remove cr/lf */
  1061.         rval = atoi(line);
  1062. #ifdef    SMTPTRACE
  1063.         if(Smtptrace)
  1064.             printf(smtp_recv,line);/* Display to user */
  1065. #endif
  1066.         if(rval >= 500) {    /* Save permanent error replies */
  1067.             char tmp[LINELEN];
  1068.             if(cb->errlog == NULLLIST) {
  1069.                 sprintf(tmp,"While talking to %s:",
  1070.                     cb->destname);
  1071.                 logerr(cb,tmp);
  1072.             }
  1073.             if(cb->buf[0] != '\0') { /* Save offending command */
  1074.                 rip(cb->buf);
  1075.                 sprintf(tmp,">>> %s",cb->buf);
  1076.                 logerr(cb,tmp);
  1077.                 cb->buf[0] = '\0';
  1078.             }
  1079.             sprintf(tmp,"<<< %s",line);
  1080.             logerr(cb,tmp);        /* save the error reply */
  1081.         }
  1082.         /* Messages with dashes are continued */
  1083.         if(line[3] != '-' && rval >= mincode)
  1084.             break;
  1085.     }
  1086.     return rval;
  1087. }
  1088.